#include "inc/my_include.h"
#include "inc/zcd_timer.h"
#include "inc/my_fifo.h"

inline int GetDaChCount(int daEn);
U16* CreateSinWave(int groupFreq, int waveFreq, int chCount, int* codeCnt);
U16* CreateRectWave(int chCount, int* codeCnt);
void ExitExe(int i);

int daEn = 0x3; //使能2个通道的DA
int rangeInx = 0;
int bc1s = 0; //1S的数据字节个数，在main函数中根据采集频率和通道号计算得出。
int fd; //设备描述符
U16* waveBuf = 0;

//写内核FIFO到半满以上：8192 * 50,在200K，2通道DA情况下，大概是8192*50/200000/2=1.024S数据量
int WriteSFifoOverH( U16* waveBuf, int codeCnt, int* writeCnt, int timeoutMS )
{
	ZcdTimer tv;//用于定时操作
	ZcdTimer_Init(&tv);
	int tempWriteCnt = 0;
	int error = 0;
	U32 canReadCnt = 0;
	while (!error)
	{
		I64 tUS = ZcdTimer_GetTimeInterval(&tv);
		if (tUS > 1000 * timeoutMS)
		{
			//如果超时则退出
			canReadCnt = EM9118_DaSFifoCanReadNumber(fd);
			U16 fCtrl = EM9118_Inw( fd, ADDR_DACTRL );
			printf( "%s:canReadCnt:%d,ctrl:%x\n", __FUNCTION__, canReadCnt, fCtrl );
			printf("time out!\n");
			error = -2;
			break;
		}
		//读出当前内核缓冲区数据个数
		canReadCnt = EM9118_DaSFifoCanReadNumber(fd);
//		printf( "%s:tempWriteCnt:%d, canReadCnt:%d, ctrl:%x\n", __FUNCTION__, tempWriteCnt, canReadCnt, fCtrl );
		if( canReadCnt > 8192 * 50 )//数据量够则不需要往里面写
		{
			//needWriteCnt = EM9118_Inw( pDev->fd, ADDR_DAFIFOCNT );
			//log_write( "%s:!(fCtrl & 0x2000),fCtrl:%x canReadCnt:%u", __FUNCTION__, fCtrl, needWriteCnt );
			//usleep(10000);
			break;
		}

/*		if( canReadCnt != tempWriteCnt )
			printf( "%s:canReadCnt:%d,tempWriteCnt:%d\n", __FUNCTION__, canReadCnt, tempWriteCnt );*/
		//向内核缓冲区写数据
		I32 rwCnt = EM9118_DaWriteSFifo(fd, waveBuf, codeCnt);
		if( rwCnt <= 0 )
		{
			printf("WriteSFifoOverH rwCnt <=0:%d!canReadCnt：%d\n", rwCnt, canReadCnt);
			break;
		}else if( rwCnt != codeCnt )
		{
			printf("WriteSFifoOverH rwCnt(%d) != codeCnt(%d)!\n", rwCnt,codeCnt);
		}
		tempWriteCnt += rwCnt;
//		printf( "tempWriteCnt:%d,canReadCnt,%d\n", tempWriteCnt, canReadCnt);
	}
	if( writeCnt )
		*writeCnt = tempWriteCnt;
	return error;
}

//写硬件FIFO接近满，为了保证波形完整性，写入个数为波形整数倍，硬件FIFO大小为2048
int WriteHFifoToFull( U16* waveBuf, int codeCnt, int* writeCnt )
{
	int i = 0;
	int tempWriteCnt = 0;
	//每个波形的数据个数不能大于1000，这样才可以保证硬件fifo里面的数据既包含了整数倍的波形，又可以多于半满
	//硬件FIFO大小位2048，但是写满后半满标志位不正常，因此，不能写到2048
	int groupCnt = 1000 / codeCnt * 2;
	if( !groupCnt )
	{
		return -1;
	}
	for( i = 0; i < groupCnt; ++i )
	{
		//往硬件缓冲区中写数据
		EM9106_DaWriteHFifo(fd, waveBuf, codeCnt);
		tempWriteCnt += codeCnt;
	}

	if( writeCnt )
		*writeCnt = tempWriteCnt;
//	printf( "WriteHFifoToFull:tempWriteCnt:%d\n", tempWriteCnt);
	return 0;
}

int main(int argc, char *argv[])
{
	fd = EM9118_Init();
	//先禁止DA输出
	EM9106_DaSetEnCh(fd, 0);
	//禁止DA中断
	EM9118BD_DaIrqEnable( fd, 0 );
	//初始化内核缓冲区，内核缓冲区大小固定为819200
	int daChCount = GetDaChCount(daEn);
	//清空硬件FIFO
	EM9106_DaHFifoClear(fd);
	//清空DA内核FIFO
	EM9118_DaSFifoClear(fd);
	//设置采集范围
	EM9106_DaSetRange(fd, 0);
	//设置采集频率
	printf( "frequency:" );
	int groupFreq = 200000;
	scanf( "%d", &groupFreq );
	int groupFreqDiv = 36000000 / groupFreq; //求出分频系数
	EM9106_DaSetFreqDiv(fd, groupFreqDiv);
	int codeCnt;
	//生成方波
	//waveBuf = CreateRectWave(daChCount, &codeCnt);
	//生成周期波每个周期100个点
	waveBuf = CreateSinWave( groupFreq,groupFreq/100,2,&codeCnt);
	//硬件FIFO里面填充数据，这样使能DA定时输出后就可以自动从FIFO里面读取值来设置DA了
	//先想硬件缓冲区写数据
	int hfifoWriteCnt;
	WriteHFifoToFull( waveBuf, codeCnt, &hfifoWriteCnt );
	//查看一些寄存器定义，注意EM9106_DaHFifoCanWriteCnt返回值有的时候可能不正确，因此不能作为写入依据
	U16 canWriteCnt;
/*	EM9106_DaHFifoCanWriteCnt(fd, &canWriteCnt);
	U16 fCtrl = EM9118_Inw(fd, ADDR_DACTRL);
	U16 cCtrl = EM9118_Inw(fd, ADDR_CTRLCODE);
	printf("%s:EM9106_DaHFifoCanWriteCnt canWriteCnt:%d,ctrl:%x,cCtrl:%x\n", __FUNCTION__, canWriteCnt, fCtrl, cCtrl);*/
	//写软件FIFO到半满以上
	int writeCnt = 0;
	int error = WriteSFifoOverH( waveBuf, codeCnt, &writeCnt, 1000 );
	U32 canReadCnt = EM9118_DaSFifoCanReadNumber( fd );

	F64 allCnt = 0;//hfifoWriteCnt + writeCnt;
	ZcdTimer tv;
	ZcdTimer_Init(&tv);
	//启动输出
	if( !error )
	{
		//使能DA中断
		EM9118BD_DaIrqEnable( fd, 1 );
		//设置通道使能
		EM9106_DaSetEnCh(fd, daEn);
		EM9106_DaStart(fd);
	}
	//计算每秒钟需要多少字节数
	I64 oldUS = ZcdTimer_GetTimeInterval(&tv);
	while (1 )
	{
		U32 beforeCanReadCnt = EM9118_DaSFifoCanReadNumber( fd );
//		printf("%s:beforeCanReadCnt:%d,ctrl:%x,cCtrl:%x\n", __FUNCTION__, beforeCanReadCnt, fCtrl, cCtrl);
		//写软件FIFO到半满以上
		int error = WriteSFifoOverH(waveBuf, codeCnt, &writeCnt, 1000);
		if( writeCnt > 0 )
		{
			allCnt += writeCnt;
			I64 tUS = ZcdTimer_GetTimeInterval(&tv);
//			if( tUS - oldUS > 1000000 )
			{
				F64 cntPerS = allCnt / (tUS / 1000000.0);
				oldUS = tUS;
				printf("beforeCanReadCnt:%d,writeCnt:%d, cntPerS:%0.0f \n", beforeCanReadCnt, writeCnt, cntPerS);
			}
			//防止定时器溢出
			if( tUS > 1000000000 )
			{
				ZcdTimer_Init(&tv);
				allCnt = 0;
			}
		}
		usleep(500000);
	}
	//下面函数时退出是停止DA输出时需要操作的函数，本程序不会执行到这里
	getchar();
	EM9106_DaStop(fd);
	EM9106_DaSetEnCh(fd, 0);
	//禁止DA中断
	EM9118BD_DaIrqEnable( fd, 0 );
	return 0;
}

int GetDaChCount(int daEn)
{ //本函数得到所有进入fifo的通道数量，以16位整型为一个通道
	int daChCnt = 0;
	int i = 0;
	for (i = 0; i < DA_CH_COUNT; ++i)
	{
		if ((daEn >> i) & 1)
			++daChCnt;
	}
	return daChCnt;
}

//本函数创建1通道锯齿波，2通道正弦波
U16* CreateSinWave(int groupFreq, int waveFreq, int chCount, int* codeCnt)
{
	printf( "DA Freq:%d, Wave Freq:%d\n", groupFreq, waveFreq );
	//一个周期有多少个数据
	int waveCnt = groupFreq / waveFreq;
	if (waveCnt < 10 || waveCnt > 1024)
	{ //一个周期如果小于10个点，波形会比较难看
		printf("waveCnt < 10!\n");
		return 0;
	}
	else if (waveCnt * chCount > 1024)
	{ //一个周期如果大于1024，往fifo里面写的时候程序会比较复杂，所以限制在1024以下
		printf("waveCnt * chCount > 1024\n");
		return 0;
	}
	U16* waveBuf = malloc(waveCnt * chCount * sizeof(U16));
	if (!waveBuf)
	{
		printf("waveBuf malloc fails\n");
		return 0;
	}
	//1通道正弦波，2通道三角波
	int codeInx = 0;
	int i;
	for ( i = 0; i < waveCnt; ++i)
	{
		int j;
		for ( j = 0; j < chCount; ++j)
		{
			F64 para = 2 * 3.1415926 * i / waveCnt;
			if (j % 2)
			{//通道2
				waveBuf[codeInx++] = (sin(para) + 1) * 32767;
			}
			else
			{//通道1
				waveBuf[codeInx++] = (U16)(i * 65535.0 / waveCnt);
			}
//			printf( "%2d:%6d ", i, waveBuf[codeInx-1] );
		}
	}
	printf( "\n" );
	*codeCnt = codeInx;
	return waveBuf;
}

//本函数创建方波，频率为DA输出频率的一半
U16* CreateRectWave(int chCount, int* codeCnt)
{
	//每个通道产生128个数据
	int waveCnt = 128;
	U16* waveBuf = malloc(waveCnt * chCount * sizeof(U16));
	if (!waveBuf)
	{
		printf("waveBuf malloc fails\n");
		return 0;
	}
	//相邻数据为最大值和最小值，这样就可以产生方波。相邻通道相位是180°
	int codeInx = 0;
	int i;
	for ( i = 0; i < waveCnt; ++i)
	{
		int j;
		for (j = 0; j < chCount; ++j)
		{
			if (j % 2)
				waveBuf[codeInx++] = (i % 2) * 65535;
			else
				waveBuf[codeInx++] = ((i+1) % 2) * 65535;
//			printf( "%d ", waveBuf[codeInx-1] );
		}
	}
//	printf( "\n" );
	*codeCnt = codeInx;
	return waveBuf;
}
